package club.jdiy.utils.poi;

import java.lang.reflect.Method;

/**
 * Excel/CSV 导出工具类的表头MetaSet信息
 * 其中：<br/>
 * head: 表格标题头文字
 * field:实体字段名
 * width: 用于导出时指定列宽度(px). 默认为0,表示使用默认宽度
 * fmt: 值格式化处理接口类.(此接口有一个fmt方法，传入要格式化的值对象，返回格式化后的值对象)
 *
 * @author ziquee(子秋) QQ号:39886616 主页: http://www.jdiy.club
 * @version 20201016
 */
@SuppressWarnings("ALL")
public class MetaSet {
    private String head;
    private String field;
    private int width=150;
    private Formatter fmt;

    public MetaSet(String head, Formatter fmt) {
        this.head = head;
        this.fmt = fmt;
    }

    public MetaSet(String head, String field) {
        this.head = head;
        this.field = field;
    }

    public MetaSet(String head, int width, Formatter fmt) {
        this(head, fmt);
        this.width = width;
    }

    public MetaSet(String head, int width, String field) {
        this(head, field);
        this.width = width;
    }

    /**
     * Excel表格头文字
     *
     * @return Excel表格头文字
     */
    public String getHead() {
        return head;
    }

    /**
     * Excel表格列宽(in px)
     *
     * @return Excel表格列宽
     */
    public int getWidth() {
        return width;
    }

    /**
     * 值格式化输出处理接口
     *
     * @return Formatter
     */
    @SuppressWarnings("unchecked")
    public Formatter getFormatter() {
        if (fmt == null) {
            fmt = new Formatter() {
                @Override
                public Object fmt(Object o) {
                    return invoke(o, field);
                }

                private Object invoke(Object bean, String field) {
                    String member;
                    if (field.contains(".")) {
                        member = field.substring(field.indexOf(".") + 1);
                        field = field.substring(0, field.indexOf("."));
                    } else {
                        member = "";
                    }

                    String uField;
                    if (field.length() >= 2) {
                        String f2 = field.substring(1, 2);
                        if (f2.equals(f2.toUpperCase())) uField = field;// aAxxx ->  getaAxx()
                        else uField = field.substring(0, 1).toUpperCase() + field.substring(1);
                    } else {
                        uField = field.toUpperCase();
                    }
                    String getName1 = "get" + uField;
                    Class tCls = bean.getClass();
                    Method getMethod;
                    Object ret;
                    try {
                        try {
                            getMethod = tCls.getMethod(getName1);
                            ret = getMethod.invoke(bean);
                        } catch (NoSuchMethodException ignore) {
                            String getName2 = "is" + uField;
                            try {
                                getMethod = tCls.getMethod(getName2);
                                ret = getMethod.invoke(bean);
                            } catch (NoSuchMethodException nsme) {
                                try {
                                    try {
                                        getMethod = tCls.getMethod("get", String.class);
                                        ret = getMethod.invoke(bean, field);
                                    } catch (NoSuchMethodException ignorex) {
                                        getMethod = tCls.getMethod("get", Object.class);
                                        ret = getMethod.invoke(bean, field);
                                    }
                                } catch (NoSuchMethodException nsme1) {
                                    nsme1.printStackTrace();
                                    throw new NoSuchMethodError("No getter: '" +
                                            getName1 + "()' or '" + getName2 +
                                            "()' or 'get(String)' or 'get(Object)' of class:" + bean.getClass().getName());
                                }
                            }
                        }
                        if (ret == null) return null;
                        else return "".equals(member) ? ret : invoke(ret, member);

                    } catch (Exception e) {
                        throw new RuntimeException("get field '" + field + "' failed.", e.getCause());
                    }
                }
            };
        }
        return fmt;
    }
}
